/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */
package net.l1j.server.model.instance;

import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Logger;

import net.l1j.server.IdFactory;
import net.l1j.server.model.L1World;
import net.l1j.server.model.instance.L1PcInstance;
import net.l1j.server.serverpackets.S_DoActionGFX;
import net.l1j.server.serverpackets.S_DollPack;
import net.l1j.server.serverpackets.S_SkillSound;
import net.l1j.server.templates.L1Npc;
import net.l1j.thread.ThreadPoolManager;
import net.l1j.util.RandomArrayList;

import static net.l1j.server.ActionCodes.*;

public class L1DollInstance extends L1NpcInstance {
	private static final long serialVersionUID = 1L;

	public static final int DOLLTYPE_BUGBEAR = 0; // バグベアー
	public static final int DOLLTYPE_SUCCUBUS = 1; // サキュバス
	public static final int DOLLTYPE_WAREWOLF = 2; // ウェアウルフ
	public static final int DOLLTYPE_ELDER = 3; // エルダー
	public static final int DOLLTYPE_CRUSTANCEAN = 4; // クラスタシアン
	public static final int DOLLTYPE_GOLEM = 5; // ゴーレム
	public static final int DOLLTYPE_SEADANCER = 6; // シーダンサー
	public static final int DOLLTYPE_SNOWMAN = 7; // イエティ
	public static final int DOLLTYPE_SERPENTWOMAN = 8; // ラミア
	public static final int DOLLTYPE_COCKATRICE = 9; // コカトリス
	public static final int DOLLTYPE_SCARECROW = 10; // かかし
	public static final int DOLLTYPE_SPARTOI = 11; // スパルトイ
	public static final int DOLLTYPE_LICH = 12; // リッチ
	public static final int DOLLTYPE_IRONGATES_SNOWMAN = 13; // 鋼鉄ギルドのイエティ
	public static final int DOLLTYPE_PRINCESS = 14; // プリンス
	public static final int DOLLTYPE_AZURU_HACHIRIN = 15; // アズールハッチリン
	public static final int DOLLTYPE_CRIMSON_HACHIRIN = 16; // クリムゾンハッチリン
	public static final int DOLLTYPE_MALE_HI_HACHIRIN = 17; // ハイハッチリンオス
	public static final int DOLLTYPE_FEMALE_HI_HACHIRIN = 18; // ハイハッチリンメス
	public static final int DOLLTYPE_SNOWMAN2 = 19; // スノーマン
	public static final int DOLLTYPE_FAIRY_OF_YUKIGASEENY = 20; // 雪合戦の妖精
	public static final int DOLL_TIME = 1800000;

	// BUGBEAR				重量軽減*10
	// SUCCUBUS 				MPR
	// WAREWOLF				攻撃ダメージ増加
	// ELDER					MPR
	// CRUSTANCEAN				攻撃ダメージ増加
	// GOLEM				ダメージ軽減
	// SEADANCER シーダンサー			HPR
	// SPARTOI スパルトイ			ダメージ回避

	// SNOWMANイエティ			AC増加、凍結耐性増加
	// SERPENTWOMAN ラミア　			毒付与、MPR増加*4
	// COCKATRICE コカトリス			弓命中増加、弓ダメージ増加
	// SCARECROW 案山子			スタン耐性増加、HPR*20　
	// LICH リッチ　				MPR増加*20、
	// IRONGATES_SNOWMAN			AC増加、攻撃ダメージ増加
	// PRINCESS プリンス　			HPR増加*20、攻撃ダメージ増加

	// AZURU_HACHIRIN			ItemMake、HPR増加*20、重量軽減*15
	// CRIMSON_HACHIRIN			ItemMake、MPR増加*10、重量軽減*15
	// MALE_HI_HACHIRIN			ItemMake、MPR増加*5、重量軽減*10
	// FEMALE_HI_HACHIRIN			ItemMake、MPR増加*5、重量軽減*10
	private static Logger _log = Logger.getLogger(L1DollInstance.class
			.getName());
	private ScheduledFuture<?> _dollFuture;
	private int _dollType;
	private int _itemObjId;
	private static final int[] DollAction = { ACTION_Think, ACTION_Aggress,
			ACTION_Salute, ACTION_Cheer };
	private int sleeptime_PT = 10;

	// ターゲットがいない場合の処理
	@Override
	public boolean noTarget() {
		if (_master.isDead()) {
			deleteDoll();
			return true;
		} else if (_master != null && _master.getMapId() == getMapId()) {
			int dir = moveDirection(_master.getX(), _master.getY());
			if (dir == -1) {
				deleteDoll();
				return true;
			} else {
				if (getLocation().getTileLineDistance(_master.getLocation()) > 3) {
					setDirectionMove(dir);
					setSleepTime(calcSleepTime(getPassispeed(), MOVE_SPEED));
				} else {
					if (sleeptime_PT == 0) {
						broadcastPacket(new S_DoActionGFX(getId(),
								DollAction[RandomArrayList.getInt(4)]));
						sleeptime_PT = RandomArrayList.getInc(20, 10);
					} else {
						--sleeptime_PT;
						setSleepTime(500);
					}
				}
			}
		} else {
			deleteDoll();
			return true;
		}
		return false;
	}

	// 時間計測用
	class DollTimer implements Runnable {
		@Override
		public void run() {
			if (_destroyed) { // 既に破棄されていないかチェック
				return;
			}
			deleteDoll();
		}
	}

	public L1DollInstance(L1Npc template, L1PcInstance master, int dollType,
			int itemObjId) {
		super(template);
		setId(IdFactory.getInstance().nextId());

		setDollType(dollType);
		setItemObjId(itemObjId);
		_dollFuture = ThreadPoolManager.getInstance().schedule(new DollTimer(),
				DOLL_TIME);

		setMaster(master);
		setX(RandomArrayList.getInc(5, master.getX() - 2));
		// master.getX() + RandomArrayList.getInt(2));
		setY(RandomArrayList.getInc(5, master.getY() - 2));
		// master.getY() + RandomArrayList.getInt(2));
		setMap(master.getMapId());
		setHeading(RandomArrayList.getInt(8));
		setLightSize(template.getLightSize());

		L1World.getInstance().storeObject(this);
		L1World.getInstance().addVisibleObject(this);
		for (L1PcInstance pc : L1World.getInstance().getRecognizePlayer(this)) {
			onPerceive(pc);
		}
		master.addDoll(this);
		if (!isAiRunning()) {
			startAI();
		}
		if (isMpRegeneration()) { // マジックドール　MPR開始
			master.startMpRegenerationByDoll();
		}

		if (isHpRegeneration()) { // マジックドール HPR開始
			master.startHpRegenerationByDoll();
		}

		if (isItemMake()) { // マジックドール アイテム製作開始
			master.startItemMakeByDoll();
		}

	}

	public void deleteDoll() {
		if (isMpRegeneration()) { // マジックドール　MPR停止
			((L1PcInstance) _master).stopMpRegenerationByDoll();
		}

		if (isHpRegeneration()) { // マジックドール　HPR停止
			((L1PcInstance) _master).stopHpRegenerationByDoll();
		}

		if (isItemMake()) { // マジックドール　製作停止
			((L1PcInstance) _master).stopItemMakeByDoll();
		}

		_master.getDollList().remove(getId());
		deleteMe();
	}

	@Override
	public void onPerceive(L1PcInstance perceivedFrom) {
		perceivedFrom.addKnownObject(this);
		perceivedFrom.sendPackets(new S_DollPack(this, perceivedFrom));
	}

	@Override
	public void onItemUse() {
		if (!isActived()) {
			// １００％の確率でヘイストポーション使用
			useItem(USEITEM_HASTE, 100);
		}
	}

	@Override
	public void onGetItem(L1ItemInstance item) {
		if (getNpcTemplate().get_digestitem() > 0) {
			setDigestItem(item);
		}
		if (Arrays.binarySearch(haestPotions, item.getItem().getItemId()) >= 0) {
			useItem(USEITEM_HASTE, 100);
		}
	}

	public int getDollType() {
		return _dollType;
	}

	public void setDollType(int i) {
		_dollType = i;
	}

	public int getItemObjId() {
		return _itemObjId;
	}

	public void setItemObjId(int i) {
		_itemObjId = i;
	}

	public int getDamageByDoll() { // 攻撃ダメージ増加 type
		int damage = 0;
		if (getDollType() == DOLLTYPE_WAREWOLF
				|| getDollType() == DOLLTYPE_CRUSTANCEAN
				|| getDollType() == DOLLTYPE_IRONGATES_SNOWMAN 
				|| getDollType() == DOLLTYPE_PRINCESS) {
			int chance = RandomArrayList.getInc(100, 1);
			if (chance <= 3) {
				damage = 15;
				if (_master instanceof L1PcInstance) {
					L1PcInstance pc = (L1PcInstance) _master;
					pc.sendPackets(new S_SkillSound(_master.getId(), 6319));
				}
				_master.broadcastPacket(new S_SkillSound(_master.getId(), 6319));
			}
		} else if (getDollType() == DOLLTYPE_SNOWMAN2) {
			damage = 2;
		}
		return damage;
	}

	public boolean isMpRegeneration() { // MPR_type
		boolean isMpRegeneration = false;
		if (getDollType() == DOLLTYPE_SUCCUBUS
				|| getDollType() == DOLLTYPE_ELDER
				|| getDollType() == DOLLTYPE_FAIRY_OF_YUKIGASEENY){
			isMpRegeneration = true;
		}
		return isMpRegeneration;
	}

	// MP回復量の計算
	public static int getMpByDoll(L1PcInstance _master) {
		int s = 0;
		s += getTypeCountByDoll(_master.getDollList(), DOLLTYPE_SUCCUBUS)*15
				+ getTypeCountByDoll(_master.getDollList(),
						DOLLTYPE_ELDER) * 15
						+ getTypeCountByDoll(_master.getDollList(),
								DOLLTYPE_FAIRY_OF_YUKIGASEENY) * 10;
		return s;		
	}
	
	public boolean isHpRegeneration() { // HPR_type
		boolean isHpRegeneration = false;
		if (getDollType() == DOLLTYPE_SEADANCER || getDollType() == DOLLTYPE_SERPENTWOMAN) {
			isHpRegeneration = true;
		}
		return isHpRegeneration;
	}

	public boolean isItemMake() { // TODO ItemMake_type
		boolean isItemMake = false;
		if (getDollType() == DOLLTYPE_AZURU_HACHIRIN
				|| getDollType() == DOLLTYPE_CRIMSON_HACHIRIN
				|| getDollType() == DOLLTYPE_MALE_HI_HACHIRIN
				|| getDollType() == DOLLTYPE_FEMALE_HI_HACHIRIN) {
			isItemMake = true;
		}
		return isItemMake;
	}

	public int getDamageReductionByDoll() { // ダメージ軽減　type
		int damageReduction = 0;
		if (getDollType() == DOLLTYPE_GOLEM) {
			int chance = RandomArrayList.getInc(100, 1);
			if (chance <= 4) {
				damageReduction = 15;
				if (_master instanceof L1PcInstance) {
					L1PcInstance pc = (L1PcInstance) _master;
					pc.sendPackets(new S_SkillSound(_master.getId(), 6320));
				}
				_master
						.broadcastPacket(new S_SkillSound(_master.getId(), 6320));
			}
		}
		return damageReduction;
	}

	public int getDamageEvasionByDoll() { // TODO ダメージ回避　type
		int damageEvasion = 0;
		if (getDollType() == DOLLTYPE_SPARTOI) {
			int chance = RandomArrayList.getInc(100, 1);
			if (chance <= 4) {
				damageEvasion = 1;
				if (_master instanceof L1PcInstance) {
					L1PcInstance pc = (L1PcInstance) _master;
					pc.sendPackets(new S_SkillSound(_master.getId(), 6320)); // TODO エフェクト不明のため代用
				}
				_master
						.broadcastPacket(new S_SkillSound(_master.getId(), 6320));
			}
		}
		return damageEvasion;
	}

	public int getPoisonByDoll() { // TODO 毒付与　type
		int damagePoison = 0;
		if (getDollType() == DOLLTYPE_SERPENTWOMAN) {
			int chance = RandomArrayList.getInc(100, 1);
			if (chance <= 60) {
				damagePoison = 1;
				}
			}
		return damagePoison;
	}

	private static int getTypeCountByDoll(Map<Integer, L1DollInstance> dolls, int type) {
		int s = 0;
		for (Object obj : dolls.values().toArray()) {
			if (((L1DollInstance) obj).getDollType() == type) {
				s++;
			}
		}
		return s;
	}

	private static int getTypeCountByDoll(Map<Integer, L1DollInstance> dolls, int type, int type1) {
		int s = 0;
		for (Object obj : dolls.values().toArray()) {
			if (((L1DollInstance) obj).getDollType() == type || ((L1DollInstance) obj).getDollType() == type1) {
				s++;
			}
		}
		return s;
	}

	// 弓命中増加　type
	public static int getBowHitAddByDoll(L1PcInstance _master) {
		int s = 0;
		s += getTypeCountByDoll(_master.getDollList(), DOLLTYPE_COCKATRICE)
		+ getTypeCountByDoll(_master.getDollList(),
				DOLLTYPE_FAIRY_OF_YUKIGASEENY) * 7;
		return s;
	}

	// 弓ダメージ増加　type
	public static int getBowDamageByDoll(L1PcInstance _master) {
		int s = 0;
		s += getTypeCountByDoll(_master.getDollList(), DOLLTYPE_COCKATRICE)
		+ getTypeCountByDoll(_master.getDollList(),
				DOLLTYPE_SNOWMAN2) * 2;
		return s;
	}

	// AC増加　type
	public static int getAcByDoll(L1PcInstance _master) {
		int s = 0;
		s -= (getTypeCountByDoll(_master.getDollList(), DOLLTYPE_SNOWMAN)
				- getTypeCountByDoll(_master.getDollList(), DOLLTYPE_IRONGATES_SNOWMAN));
		return s;
	}

	// 凍結耐性増加　type
	public static int getRegistFreezeByDoll(L1PcInstance _master) {
		int s = 0;
		s -= (getTypeCountByDoll(_master.getDollList(), DOLLTYPE_SNOWMAN)) * 10;
		return s;
	}

	// MPR増加　type
	public static int getMprByDoll(L1PcInstance _master) {
		int s = 0;
		s += (getTypeCountByDoll(_master.getDollList(),
				DOLLTYPE_CRIMSON_HACHIRIN) * 10 + (getTypeCountByDoll(_master
				.getDollList(), DOLLTYPE_MALE_HI_HACHIRIN) + getTypeCountByDoll(
				_master.getDollList(), DOLLTYPE_FEMALE_HI_HACHIRIN)) * 5
				+ getTypeCountByDoll(_master.getDollList(),
						DOLLTYPE_SERPENTWOMAN) * 4
						+ getTypeCountByDoll(_master.getDollList(),
								DOLLTYPE_SNOWMAN2) * 2);
		return s;
	}

	// HPR増加　type
	public static int getHprByDoll(L1PcInstance _master) {
		int s = 0;
		s += (getTypeCountByDoll(_master.getDollList(), DOLLTYPE_AZURU_HACHIRIN) * 20
				+ getTypeCountByDoll(_master.getDollList(), DOLLTYPE_SCARECROW) * 20
				+ getTypeCountByDoll(_master.getDollList(), DOLLTYPE_PRINCESS) * 20);
		return s;
	}

	// 重量軽減　type
	public static int getWeightReductionByDoll(L1PcInstance _master) {
		int s = 0;
		s += (getTypeCountByDoll(_master.getDollList(),DOLLTYPE_BUGBEAR)
		+ getTypeCountByDoll(_master.getDollList(), DOLLTYPE_MALE_HI_HACHIRIN) 
		+ getTypeCountByDoll(_master.getDollList(), DOLLTYPE_FEMALE_HI_HACHIRIN)
		+ getTypeCountByDoll(_master.getDollList(), DOLLTYPE_CRIMSON_HACHIRIN) 
		+ getTypeCountByDoll(_master.getDollList(), DOLLTYPE_AZURU_HACHIRIN)) * 10;
		return s;
	}
}
